1   /***
2    * ASM: a very small and fast Java bytecode manipulation framework
3    * Copyright (c) 2000-2011 INRIA, France Telecom
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions
8    * are met:
9    * 1. Redistributions of source code must retain the above copyright
10   *    notice, this list of conditions and the following disclaimer.
11   * 2. Redistributions in binary form must reproduce the above copyright
12   *    notice, this list of conditions and the following disclaimer in the
13   *    documentation and/or other materials provided with the distribution.
14   * 3. Neither the name of the copyright holders nor the names of its
15   *    contributors may be used to endorse or promote products derived from
16   *    this software without specific prior written permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28   * THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.apache.tapestry5.internal.plastic.asm.optimizer;
31  
32  import java.util.HashMap;
33  
34  import org.apache.tapestry5.internal.plastic.asm.AnnotationVisitor;
35  import org.apache.tapestry5.internal.plastic.asm.Attribute;
36  import org.apache.tapestry5.internal.plastic.asm.FieldVisitor;
37  import org.apache.tapestry5.internal.plastic.asm.Label;
38  import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
39  import org.apache.tapestry5.internal.plastic.asm.Opcodes;
40  import org.apache.tapestry5.internal.plastic.asm.Type;
41  import org.apache.tapestry5.internal.plastic.asm.TypePath;
42  import org.apache.tapestry5.internal.plastic.asm.commons.Remapper;
43  import org.apache.tapestry5.internal.plastic.asm.commons.RemappingMethodAdapter;
44  
45  /**
46   * A {@link MethodVisitor} that renames fields and methods, and removes debug
47   * info.
48   * 
49   * @author Eugene Kuleshov
50   */
51  public class MethodOptimizer extends RemappingMethodAdapter implements Opcodes {
52  
53      private final ClassOptimizer classOptimizer;
54  
55      public MethodOptimizer(ClassOptimizer classOptimizer, int access,
56              String desc, MethodVisitor mv, Remapper remapper) {
57          super(Opcodes.ASM5, access, desc, mv, remapper);
58          this.classOptimizer = classOptimizer;
59      }
60  
61      // ------------------------------------------------------------------------
62      // Overridden methods
63      // ------------------------------------------------------------------------
64  
65      @Override
66      public void visitParameter(String name, int access) {
67          // remove parameter info
68      }
69  
70      @Override
71      public AnnotationVisitor visitAnnotationDefault() {
72          // remove annotations
73          return null;
74      }
75  
76      @Override
77      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
78          // remove annotations
79          return null;
80      }
81  
82      @Override
83      public AnnotationVisitor visitTypeAnnotation(int typeRef,
84              TypePath typePath, String desc, boolean visible) {
85          return null;
86      }
87  
88      @Override
89      public AnnotationVisitor visitParameterAnnotation(final int parameter,
90              final String desc, final boolean visible) {
91          // remove annotations
92          return null;
93      }
94  
95      @Override
96      public void visitLocalVariable(final String name, final String desc,
97              final String signature, final Label start, final Label end,
98              final int index) {
99          // remove debug info
100     }
101 
102     @Override
103     public void visitLineNumber(final int line, final Label start) {
104         // remove debug info
105     }
106 
107     @Override
108     public void visitFrame(int type, int local, Object[] local2, int stack,
109             Object[] stack2) {
110         // remove frame info
111     }
112 
113     @Override
114     public void visitAttribute(Attribute attr) {
115         // remove non standard attributes
116     }
117 
118     @Override
119     public void visitLdcInsn(Object cst) {
120         if (!(cst instanceof Type)) {
121             super.visitLdcInsn(cst);
122             return;
123         }
124 
125         // transform Foo.class for 1.2 compatibility
126         String ldcName = ((Type) cst).getInternalName();
127         String fieldName = "class$" + ldcName.replace('/', '$');
128         if (!classOptimizer.syntheticClassFields.contains(ldcName)) {
129             classOptimizer.syntheticClassFields.add(ldcName);
130             FieldVisitor fv = classOptimizer.syntheticFieldVisitor(ACC_STATIC
131                     | ACC_SYNTHETIC, fieldName, "Ljava/lang/Class;");
132             fv.visitEnd();
133         }
134 
135         String clsName = classOptimizer.clsName;
136         mv.visitFieldInsn(GETSTATIC, clsName, fieldName, "Ljava/lang/Class;");
137     }
138     
139     @Override
140     public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
141         // rewrite boxing method call to use constructor to keep 1.3/1.4 compatibility
142         String[] constructorParams;
143         if (opcode == INVOKESTATIC && name.equals("valueOf") &&
144             (constructorParams = BOXING_MAP.get(owner + desc)) != null) {
145             String type = constructorParams[0];
146             String initDesc = constructorParams[1];
147             super.visitTypeInsn(NEW, type);
148             super.visitInsn(DUP);
149             super.visitInsn((initDesc == "(J)V" || initDesc == "(D)V")? DUP2_X2: DUP2_X1);
150             super.visitInsn(POP2);
151             super.visitMethodInsn(INVOKESPECIAL, type, "<init>", initDesc, false);
152             return;
153         }
154         super.visitMethodInsn(opcode, owner, name, desc, itf);
155     }
156     
157     private static final HashMap<String, String[]> BOXING_MAP;
158     static {
159         String[][] boxingNames = {
160             // Boolean.valueOf is 1.4 and is used by the xml package, so no rewrite
161             { "java/lang/Byte",      "(B)V" },
162             { "java/lang/Short",     "(S)V" },
163             { "java/lang/Character", "(C)V" },
164             { "java/lang/Integer",   "(I)V" },
165             { "java/lang/Long",      "(J)V" },
166             { "java/lang/Float",     "(F)V" },
167             { "java/lang/Double",    "(D)V" },
168         };
169         HashMap<String, String[]> map = new HashMap<String, String[]>();
170         for(String[] boxingName: boxingNames) {
171             String wrapper = boxingName[0];
172             String desc = boxingName[1];
173             String boxingMethod = wrapper + '(' + desc.charAt(1) + ")L" + wrapper + ';';
174             map.put(boxingMethod, boxingName);
175         }
176         BOXING_MAP = map;
177     }
178 }